package com.gitee.wsl.android.ui.activity

import android.content.Context
import android.content.Intent
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContract
import androidx.core.app.ActivityOptionsCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import java.util.UUID
import kotlin.properties.Delegates

fun ComponentActivity.simpleActivityForResultLauncher(
    intent: Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> Unit
): ActivityResultLauncher<Unit> {
    return activityForResultLauncher(
        createIntent = { _, _ -> intent },
        onActivityResult = onActivityResult
    )
}

fun Fragment.simpleActivityForResultLauncher(
    intent: Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> Unit
): ActivityResultLauncher<Unit> {
    return activityForResultLauncher(
        createIntent = { _, _ -> intent },
        onActivityResult = onActivityResult
    )
}

fun <I> ComponentActivity.activityForResultLauncher(
    createIntent: (context: Context, input: I) -> Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> Unit
): ActivityResultLauncher<I> {
    return registerForActivityResult(
        activityResultContract(
            createIntent = createIntent,
            onActivityResult = onActivityResult
        )
    ) {
    }
}

fun <I,O> ComponentActivity.activityRegistryForResultLauncher(
    createIntent: (context: Context, input: I) -> Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> O,
    callback:ActivityResultCallback<O>
): ActivityResultLauncher<I> {
    var launcher by Delegates.notNull<ActivityResultLauncher<I>>()
    val nextKey = UUID.randomUUID().toString()
    launcher =activityResultRegistry.register(
        nextKey,
        activityRegisterResultContract(
            createIntent = createIntent,
            onActivityResult = onActivityResult
        )
    ) { result ->
        callback.onActivityResult(result)
        launcher.unregister()
    }
    lifecycle.addObserver(object : LifecycleEventObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                launcher.unregister()
                lifecycle.removeObserver(this)
            }
        }
    })
    return launcher
}

fun <I,O> ComponentActivity.activityRegistryForResultLauncher(
    contract:ActivityResultContract<I, O>,
    callback:ActivityResultCallback<O>
): ActivityResultLauncher<I> {
    var launcher by Delegates.notNull<ActivityResultLauncher<I>>()
    val nextKey = UUID.randomUUID().toString()
    launcher =activityResultRegistry.register(
        nextKey,
        contract
    ) { result ->
        callback.onActivityResult(result)
        launcher.unregister()
    }
    lifecycle.addObserver(object : LifecycleEventObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                launcher.unregister()
                lifecycle.removeObserver(this)
            }
        }
    })
    return launcher
}

fun <I,O> Fragment.activityRegistryForResultLauncher(
    contract:ActivityResultContract<I, O>,
    callback:ActivityResultCallback<O>
): ActivityResultLauncher<I> {
    return requireActivity().activityRegistryForResultLauncher(contract,callback)
}

fun <I> Fragment.activityForResultLauncher(
    createIntent: (context: Context, input: I) -> Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> Unit
): ActivityResultLauncher<I> {
    return registerForActivityResult(
        activityResultContract(
            createIntent = createIntent,
            onActivityResult = onActivityResult
        )
    ) {
    }
}

private fun <I> activityResultContract(
    createIntent: (context: Context, input: I) -> Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> Unit
): ActivityResultContract<I, Unit> {
    return object : ActivityResultContract<I, Unit>() {
        override fun createIntent(
            context: Context,
            input: I
        ): Intent {
            return createIntent(context, input)
        }

        override fun parseResult(
            resultCode: Int,
            intent: Intent?
        ) {
            onActivityResult(resultCode, intent)
        }
    }
}

private fun <I,O> activityRegisterResultContract(
    createIntent: (context: Context, input: I) -> Intent,
    onActivityResult: (resultCode: Int, data: Intent?) -> O
): ActivityResultContract<I, O> {
    return object : ActivityResultContract<I, O>() {
        override fun createIntent(
            context: Context,
            input: I
        ): Intent {
            return createIntent(context, input)
        }

        override fun parseResult(
            resultCode: Int,
            intent: Intent?
        ): O {
            return onActivityResult(resultCode, intent)
        }
    }
}

fun <I> ActivityResultLauncher<I>.safeLaunch(
    input: I,
    onError: (Throwable) -> Unit = {
    //it.message?.showToast()
    }
) {
    runCatching {
        launch(input)
    }.onFailure {
        // e.g. No Activity found to handle Intent
        it.printStackTrace()
        onError.invoke(it)
    }
}

fun <I> ActivityResultLauncher<I>.safeLaunch(
    input: I,
    options: ActivityOptionsCompat,
    onError: (Throwable) -> Unit = {
        //it.message?.showToast()
     }
) {
    runCatching {
        launch(input, options)
    }.onFailure {
        // e.g. No Activity found to handle Intent
        it.printStackTrace()
        onError.invoke(it)
    }
}